package com.xiaozhi.service;

import com.xiaozhi.exception.RetryFailedException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * 重试服务类
 * 为AI服务调用提供重试机制
 */
@Service
@Slf4j
public class RetryService {
    
    private static final int MAX_RETRIES = 3;
    private static final long INITIAL_DELAY_MS = 1000; // 1秒
    private static final double BACKOFF_MULTIPLIER = 2.0;
    
    /**
     * 执行带重试的操作
     * @param operation 要执行的操作
     * @param operationName 操作名称，用于日志
     * @param <T> 返回类型
     * @return 操作结果
     */
    public <T> T executeWithRetry(Supplier<T> operation, String operationName) {
        return executeWithRetry(operation, operationName, MAX_RETRIES);
    }
    
    /**
     * 执行带重试的操作
     * @param operation 要执行的操作
     * @param operationName 操作名称，用于日志
     * @param maxRetries 最大重试次数
     * @param <T> 返回类型
     * @return 操作结果
     */
    public <T> T executeWithRetry(Supplier<T> operation, String operationName, int maxRetries) {
        Exception lastException = null;
        
        for (int attempt = 1; attempt <= maxRetries + 1; attempt++) {
            try {
                log.debug("执行操作: {} (尝试 {}/{})", operationName, attempt, maxRetries + 1);
                T result = operation.get();
                
                if (attempt > 1) {
                    log.info("操作 {} 在第 {} 次尝试后成功", operationName, attempt);
                }
                
                return result;
                
            } catch (Exception e) {
                lastException = e;
                
                if (attempt <= maxRetries) {
                    if (isRetryableException(e)) {
                        long delayMs = calculateDelay(attempt - 1);
                        log.warn("操作 {} 第 {} 次尝试失败，{}ms 后重试: {}", 
                                operationName, attempt, delayMs, e.getMessage());
                        
                        try {
                            Thread.sleep(delayMs);
                        } catch (InterruptedException ie) {
                            Thread.currentThread().interrupt();
                            throw new RuntimeException("重试被中断", ie);
                        }
                    } else {
                        log.error("操作 {} 遇到不可重试的异常: {}", operationName, e.getMessage());
                        break;
                    }
                } else {
                    log.error("操作 {} 在 {} 次尝试后最终失败", operationName, maxRetries + 1);
                }
            }
        }
        
        throw new RetryFailedException(operationName, maxRetries, lastException);
    }
    
    /**
     * 异步执行带重试的操作
     * @param operation 要执行的操作
     * @param operationName 操作名称
     * @param <T> 返回类型
     * @return CompletableFuture包装的结果
     */
    public <T> CompletableFuture<T> executeWithRetryAsync(Supplier<T> operation, String operationName) {
        return CompletableFuture.supplyAsync(() -> executeWithRetry(operation, operationName));
    }
    
    /**
     * 判断异常是否可以重试
     * @param exception 异常
     * @return 是否可重试
     */
    private boolean isRetryableException(Exception exception) {
        String message = exception.getMessage();
        if (message == null) {
            return false;
        }
        
        String lowerMessage = message.toLowerCase();
        
        // 网络相关异常可重试
        if (lowerMessage.contains("timeout") || 
            lowerMessage.contains("connection") ||
            lowerMessage.contains("network") ||
            lowerMessage.contains("socket")) {
            return true;
        }
        
        // 服务器错误可重试
        if (lowerMessage.contains("500") || 
            lowerMessage.contains("502") ||
            lowerMessage.contains("503") ||
            lowerMessage.contains("504")) {
            return true;
        }
        
        // 频率限制可重试
        if (lowerMessage.contains("rate limit") || 
            lowerMessage.contains("too many requests") ||
            lowerMessage.contains("429")) {
            return true;
        }
        
        // API密钥错误、认证失败等不可重试
        if (lowerMessage.contains("api key") ||
            lowerMessage.contains("authentication") ||
            lowerMessage.contains("unauthorized") ||
            lowerMessage.contains("401") ||
            lowerMessage.contains("403")) {
            return false;
        }
        
        // 参数错误不可重试
        if (lowerMessage.contains("400") ||
            lowerMessage.contains("bad request") ||
            lowerMessage.contains("invalid")) {
            return false;
        }
        
        // 默认可重试
        return true;
    }
    
    /**
     * 计算延迟时间（指数退避）
     * @param attemptNumber 尝试次数（从0开始）
     * @return 延迟时间（毫秒）
     */
    private long calculateDelay(int attemptNumber) {
        return (long) (INITIAL_DELAY_MS * Math.pow(BACKOFF_MULTIPLIER, attemptNumber));
    }
}